
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>


/*#define NEW	0
#define TER	1
#define MIG	2
#define BUSY	4 
#define IDLE 	5 */
#define MAX_Event 4
#define APP1	0
#define APP2	1
#define APP3	2
#define APP4	3 
#define IDLE 	5
#define BUSY    6 
#define number_of_types_of_apps 4
#define max_possible_apps 100
#define SELF_GEN 20
#define OUT_GEN 21
#define Periodic_review_event_duration 2
//define periodic review to be 2 seconds
FILE *fp,*fp2_log;

struct details_node_departure_list{
float  timings_in_departure_list;
int type_of_app;
int self; //whether same cell or handoverd call
int valid;
} ; //this is the structure of basic node which are admitted into channel


struct details_node_app_wait_list{
float  expire_time; //expire time
int type_of_app; //which type of app is it
int self;//whether same cell or handvered call
int valid; //whether this node is valid/not valid
int priority_index;
} ;//this is the structure of basic node which is admitted in the wait queue



struct details_node_departure_list global_details_node_departure_list[number_of_types_of_apps][max_possible_apps];
struct details_node_app_wait_list global_app_wait_list[number_of_types_of_apps][max_possible_apps];
int global_scheme=0;
//int type_in_departure_list[number_of_types_of_apps][max_possible_apps];
int next_event_type,no_cust_del,tot_cust,tot_req;
int flag_departure_calculated=0; //whether departure time already calculated
int global_departure_event_type,global_self=0,global_channel_or_wait=0;
int napp1_self=0,napp2_self=0,napp3_self=0,napp4_self=0;//generated data in same cell
int napp1_self_Drop=0,napp2_self_Drop=0,napp3_self_Drop=0,napp4_self_Drop=0;
int global_tempi,global_tempj,global_temp_type, global_app_wait_tempj,global_app_wait_tempi,global_app_wait_temp_app_type;//these are the indexs whose time to go out has come
int global_number_of_app_arrived=0,global_number_of_app_departured=0;
int q_len_app1=0, q_len_app2=0, q_len_app3=0,q_len_app4=0; //current queue strenght for each app  
//first hundered belongs to app1, sencond hundred app2, third hundred app3, fourth hundred app4
int channel_state;
int user_type,user_type_temp,user_type_self_temp;
int max_q_app1=2, max_q_app2=1, max_q_app3=1,max_q_app4=2; //max queue for each application
float max_q_time_app1=1.2,max_q_time_app2=1.0,max_q_time_app3=1.0,max_q_time_app4=1.3;  //max stay duration of each type of queue
int priority_app1=1,priority_app2=2,priority_app3=3,priority_app4=4;	
int napp1=0,napp2=0,napp3=0,napp4=0; //number of app for each category
int napp1_drop=0,napp2_drop=0,napp3_drop=0,napp4_drop=0;  //dropped numbers for each app
int channel_BW=384, Total_BW_APP1=0,Total_BW_APP2=0,Total_BW_APP3=0,Total_BW_APP4=0;

float time,tot_delay,tot_que,tot_ser,mean_arr_time,time_next_event[10];
float time_last_event,mean_serv_time_app1=5,mean_serv_time_app2=2,mean_serv_time_app3=3,mean_serv_time_app4=10;
float mean_arr_time = .1;
int Req_BW_APP1=20,Req_BW_APP2=40,Req_BW_APP3=10,Req_BW_APP4=60;
void initialize(void);
void timing(void);
void update_time_avg_stats(void);
void arrive(void);
void depart(void);
void report(void);
float expon(float);
void review_char(void);
void depart_app_wait(void);
int max(int a,int b,int c,int d);

int main(int argc, char *argv[])
{

tot_req=atoi(argv[1]);
char sbuf[100];
sprintf(sbuf,"log%d.txt",tot_req);
  fp=fopen(sbuf,"w");

	//printf(" How many cust?\n");
	//scanf("%d",&tot_req);
	//printf("Mean arrival time\n");
	//scanf("%f",&mean_arr_time);
	//printf("Mean service time\n");
	//scanf("%f",&mean_serv_time);


	initialize();
	while( (global_number_of_app_arrived<tot_req)||(global_number_of_app_departured+napp1_drop+napp2_drop+napp3_drop+napp4_drop< tot_req))
	{

		timing();
		update_time_avg_stats();
                printf("\n scheduler time %f tot_req %d tot arrived %d tot depart %d\n ",time,tot_req,global_number_of_app_arrived,global_number_of_app_departured); 
printf("\n depart_app_wait(void) %d %d %d %d %d %d %d %d",napp1_drop,napp2_drop,napp3_drop,napp4_drop,q_len_app1,q_len_app2,q_len_app3,q_len_app4);
		switch(next_event_type)
		{

			case 1:
				arrive();
				break;

			case 2:
				depart();
				break;
			case 3:
				review_char();
                            break;
			case 4:
				depart_app_wait();
                            break;

  
		}

	}

fclose(fp);
	report();

	return;

}


void initialize()
{
int i,j;
	time = 0.0;
	channel_state = IDLE;
	q_len_app1=0, q_len_app2=0, q_len_app3=0,q_len_app4=0;
	//max_que_len = 0;
	time_last_event = 0.0;


	no_cust_del = 0;
	//tot_delay = 0.0;
	//tot_que = 0.0;
	//tot_ser = 0.0;

	time_next_event[1] = time + expon(mean_arr_time); //packet arrival
	time_next_event[2] = 1000000.00;  //APP type 1 Departure from channel
	time_next_event[3]=time+Periodic_review_event_duration; //initialize reveiw characterstic event
		time_next_event[4] = 1000000.00;  //departure from the app wait due to timer expire
//int timings_in_departure_list[number_of_types_of_apps][max_possible_apps];
for(i=0;i<number_of_types_of_apps;i++)
for(j=0;j< max_possible_apps;j++)
{
global_details_node_departure_list[i][j].timings_in_departure_list=1000000.00;
global_details_node_departure_list[i][j].type_of_app=100;
global_details_node_departure_list[i][j].self=100;
global_details_node_departure_list[i][j].valid=0;
}



//int timings_in_departure_list[number_of_types_of_apps][max_possible_apps];
for(i=0;i<number_of_types_of_apps;i++)
for(j=0;j< max_possible_apps;j++)
{
global_app_wait_list[i][j].expire_time=1000000.00;
global_app_wait_list[i][j].type_of_app=100;
global_app_wait_list[i][j].self=100;
global_app_wait_list[i][j].valid=0;
global_app_wait_list[i][j].priority_index=100;
}


printf("Initialization\n");
flag_departure_calculated=0; //departure time is not calculated


}

void timing(void)
{

	int i;
	float min_time_next_event = 1000000.00;

	for( i=1; i<= MAX_Event; i++ )//counter runts till max types of events
	{
		if( time_next_event[i] < min_time_next_event )
		{

			min_time_next_event = time_next_event[i];
			next_event_type = i;
		}
	}

	time = min_time_next_event;


}
//this function finds out the minimum time among the departures and update it with infinity again
struct details_node_departure_list find_minimum_in_departure_list()
{


int i,j;


struct details_node_departure_list temp_result;
temp_result.timings_in_departure_list=1000000.00;
temp_result.type_of_app=100;
printf("find_minimum_in_departure_list()\n");

for(i=0;i<number_of_types_of_apps;i++)
for(j=0;j< max_possible_apps;j++)
	{
		if(global_details_node_departure_list[i][j].timings_in_departure_list< temp_result.timings_in_departure_list)
		{

		temp_result.timings_in_departure_list	= global_details_node_departure_list[i][j].timings_in_departure_list;
		temp_result.type_of_app=global_details_node_departure_list[i][j].type_of_app;
                temp_result.self=global_details_node_departure_list[i][j].self;
	       global_tempi=i;
		global_tempj=j;
		}
	}
/*for(i=0;i<number_of_types_of_apps;i++)
for(j=0;j< 20;j++)
	{
		if(global_details_node_departure_list[i][j].timings_in_departure_list< 1000000.00)
		{

		printf("1 ");
		}
	} */
printf("minimum are time %f type%d",temp_result.timings_in_departure_list,temp_result.type_of_app);

	return temp_result;
}

struct details_node_app_wait_list find_minimum_in_app_wait_list()
{


int i,j;


struct details_node_app_wait_list temp_result;
temp_result.expire_time =1000000.00;
temp_result.type_of_app=100;
printf("find_minimum_in_update_App_time_in_app_wait_list()\n");

for(i=0;i<number_of_types_of_apps;i++)
for(j=0;j< max_possible_apps;j++)
	{
		if(global_app_wait_list[i][j].expire_time< temp_result.expire_time)
		{

		temp_result.expire_time	= global_app_wait_list[i][j].expire_time;
		temp_result.type_of_app=global_app_wait_list[i][j].type_of_app;
              temp_result.self=global_app_wait_list[i][j].self;
              temp_result.priority_index=global_app_wait_list[i][j].priority_index;
	       global_app_wait_tempi=i; // todo they are used for deleting   invalid entry
		global_app_wait_tempj=j;
		global_app_wait_temp_app_type=temp_result.type_of_app;
		}
	}
/*for(i=0;i<number_of_types_of_apps;i++)
for(j=0;j< 20;j++)
	{
		if(global_details_node_departure_list[i][j].timings_in_departure_list< 1000000.00)
		{

		printf("1 ");
		}
	} */
printf("minimum are time %f type%d",temp_result.expire_time,temp_result.type_of_app);

	return temp_result;
}

//just update anywhere in the list where nothing else is updated.
void update_App_time_in_app_wait_list(int L_user_type, float L_App_time,int self_local,int priority)
{

int i,j;

float min_time_next_event = 1000000.00;
i= L_user_type;
printf("update_App_time_in_app_wait_list() app type %d  max_possible_apps  %d current time %f\n",L_user_type,max_possible_apps,time);


for(j=0;j< max_possible_apps;j++)
	{
       //  printf("test %d %d %f\n",i,j,global_details_node_departure_list[i][j].timings_in_departure_list);		
		if( (global_app_wait_list[i][j].expire_time) <= min_time_next_event-1 )
		{
		//	printf("continue %f\n",global_details_node_departure_list[i][j].timings_in_departure_list);
			continue;
		}else
		{
			//printf("break\n");
			global_app_wait_list[i][j].expire_time=L_App_time+time;
			global_app_wait_list[i][j].type_of_app=L_user_type;
			global_app_wait_list[i][j].self=self_local;			
			global_app_wait_list[i][j].priority_index=priority;
			break;
		} 
	}
}



//just update anywhere in the list where nothing else is updated.
void update_App_time_in_departure_list(int L_user_type, float L_App_time,int self_local)
{

int i,j;

float min_time_next_event = 1000000.00;
i= L_user_type;
printf("update_App_time_in_departure_list() app type %d  max_possible_apps  %d current time %f\n",L_user_type,max_possible_apps,time);


for(j=0;j< max_possible_apps;j++)
	{
       //  printf("test %d %d %f\n",i,j,global_details_node_departure_list[i][j].timings_in_departure_list);		
		if( (global_details_node_departure_list[i][j].timings_in_departure_list) <= min_time_next_event-1 )
		{
		//	printf("continue %f\n",global_details_node_departure_list[i][j].timings_in_departure_list);
			continue;
		}else
		{
			//printf("break\n");
			global_details_node_departure_list[i][j].timings_in_departure_list=L_App_time;
			global_details_node_departure_list[i][j].type_of_app=L_user_type;
global_details_node_departure_list[i][j].self=self_local;			
break;
		} 
	}
}

void update_time_avg_stats(void)
{

	float time_since_last_event;

	time_since_last_event = time - time_last_event;
	time_last_event = time;

	//tot_que += que_len * time_since_last_event;
	//tot_ser += ser_stat * time_since_last_event;

}


void arrive(void)
{
	float delay,temp_time;
	struct details_node_departure_list temp_result;
       struct details_node_app_wait_list temp_result_app_wait;
       
	user_type_temp = rand()%100;


	int i=0,j=0,self_temp,self_local;
	global_number_of_app_arrived++;
	if(global_number_of_app_arrived<=tot_req)	
		time_next_event[1] = time + expon(mean_arr_time); //calculate next arrival now itself
	else
		time_next_event[1]= 1000000.00; 


	

//----
//Application classifier
//Part 1: which application type
if(user_type_temp <= 40)
user_type=APP1;
else if ((41<= user_type_temp )&& (user_type_temp<=50))
user_type=APP2;
else if((51<= user_type_temp)&& (user_type_temp<=70))
user_type=APP3;
else if ((71<= user_type_temp)&& (user_type_temp<=100))
user_type=APP4;
printf("\n\n");
printf(" arrive () APP type %d Current Time%f Next Arrival %f\n",user_type,time,time_next_event[1]);
//----
//Part 2: whether same cell generated or outside cell generated
self_temp = rand()%100;
if(self_temp <= 80)
self_local=SELF_GEN;
else 
self_local=OUT_GEN;


		if ( user_type == APP1 )
		{         napp1++;
			Total_BW_APP1=Total_BW_APP1+Req_BW_APP1;
                        if(self_local==SELF_GEN)
			napp1_self++;
                          
		}
		if ( user_type == APP2)
		{        napp2++;
			Total_BW_APP2=Total_BW_APP2+Req_BW_APP2;
			if(self_local==SELF_GEN)
			napp2_self++;
		}
		if ( user_type == APP3)
		{       napp3++;
			Total_BW_APP3=Total_BW_APP3+Req_BW_APP3;
 			 if(self_local==SELF_GEN)
			napp3_self++;
		}
	       if ( user_type == APP4)
		{       napp4++; 
			Total_BW_APP4=Total_BW_APP4+Req_BW_APP4;
  			if(self_local==SELF_GEN)
			napp4_self++;
		}
	
        //Determine what state channel is in now
        if(channel_BW< (Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4))
	     channel_state = BUSY;
        else
	     channel_state = IDLE;



	if( channel_state == BUSY )
		{

			if ( user_type == APP1 )
			{      Total_BW_APP1=Total_BW_APP1-Req_BW_APP1;//just resetting what was done before
				
				if ( q_len_app1 >= max_q_app1) 
	                           {
					napp1_drop++;
	    				if(self_local==SELF_GEN)
					napp1_self_Drop++;			
				    }
				else 
					{
                                 update_App_time_in_app_wait_list(user_type,max_q_time_app1,self_local,priority_app1);
				
					q_len_app1++;
					}
			}

			if ( user_type == APP2 )
			{       Total_BW_APP2=Total_BW_APP2-Req_BW_APP2;//just resetting what was done before
				
				if ( q_len_app2 >= max_q_app1)  {
					napp2_drop++;
				        if(self_local==SELF_GEN)
					napp2_self_Drop++;			
				    }
				else 
					{
					 update_App_time_in_app_wait_list(user_type,max_q_time_app2,self_local,priority_app2);
					q_len_app2++;
					}
			}

			if ( user_type == APP3)
			{       Total_BW_APP3=Total_BW_APP3-Req_BW_APP3;//just resetting what was done before
				
				if ( q_len_app3 >= max_q_app1 )  {
					napp3_drop++;
	 			        if(self_local==SELF_GEN)
					napp3_self_Drop++;			
				    }
				else{
					 update_App_time_in_app_wait_list(user_type,max_q_time_app3,self_local,priority_app3);
					q_len_app3++;
					}
			}

			if ( user_type == APP4 )
			{	Total_BW_APP4=Total_BW_APP4-Req_BW_APP4;//just resetting what was done before
				if ( q_len_app4 >= max_q_app1 )  {
					napp4_drop++;
					if(self_local==SELF_GEN)
					napp4_self_Drop++;			
				    }
				else{
					 update_App_time_in_app_wait_list(user_type,max_q_time_app4,self_local,priority_app4);
					q_len_app4++;
					}
			}

			temp_result_app_wait=find_minimum_in_app_wait_list();
			time_next_event[4]=temp_result_app_wait.expire_time;
			//time_arrival[que_len] = time;
	         printf("arrive () Channel Busy APP Type %d Requested BW %d time %f \n",user_type,Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4,time);
		}
		else
		{//this case is when channel BW is available,Bandwidth already added in above step
				
			if ( user_type == APP1 )
			{
				temp_time = time + expon(mean_serv_time_app1);	
			}
			if ( user_type == APP2)
			{
				temp_time = time + expon(mean_serv_time_app2);	
			}
			if ( user_type == APP3)
			{
				temp_time = time + expon(mean_serv_time_app3);	
			}
		       if ( user_type == APP4)
			{
				temp_time= time + expon(mean_serv_time_app4);	
			}
	i=user_type;


		printf("arrive () Channel Avail: APP type%d APP Leave Time %f BW %d  Current time%f\n",user_type,temp_time,Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4,time);
	//update the time in the departure list
	update_App_time_in_departure_list(user_type,temp_time,self_local);
	//pick up latest time

	temp_result=find_minimum_in_departure_list();
	time_next_event[2]=temp_result.timings_in_departure_list;
	global_departure_event_type=temp_result.type_of_app;
	global_self=temp_result.self;
		        printf("arrive ()APP Type %d, Stay Time Min Current App:%f\n",user_type ,time_next_event[2]);
		flag_departure_calculated=1;	
		}
printf(" arrive ()APP type %d, channel_state%d, Total remaining BW %d \n",user_type,channel_state,channel_BW-(Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4));

fprintf(fp,"A %d %f %f %f %d\n",user_type,time,time_next_event[1],time_next_event[2],channel_BW-(Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4));
}
//simple algorithm
/*
1. Decrease BW based on type of APP
2. Check if Channel is still Busy
3. If channel is busy, dont take any new item from queue, just find the least departure from the departure list
4. If channel is idle, take out one item from the queue
     if this item meets the BW requiirement, take it , update in departure list, and calculate least departure
     if this item doesnt meet the BW requirement, dont take it, just drop it.    



*/

void depart(void)
{
	float min_time_next_event = 1000000.00;
	int temp_queue_type,temp_next,j;
	float temp_time;
	int i,local_app_wait_tempj,local_app_wait_tempi;
	float delay;
	struct details_node_departure_list temp_result,temp_copy;
	struct details_node_app_wait_list temp_result_app_wait;
	flag_departure_calculated=0;
	global_number_of_app_departured++;
	
	printf("\n\n");
	printf("Depart() current time %f\n",time);
	temp_copy=global_details_node_departure_list[global_tempi][global_tempj];
	global_details_node_departure_list[global_tempi][global_tempj].timings_in_departure_list=1000000.00; // now since it is anyway getting used, reset the original
	global_details_node_departure_list[global_tempi][global_tempj].type_of_app=100;
///see if channel is full or not

	if ( global_departure_event_type== APP1 )
		{
			Total_BW_APP1=Total_BW_APP1-Req_BW_APP1;
		}
		if (global_departure_event_type == APP2)
		{
			Total_BW_APP2=Total_BW_APP2-Req_BW_APP2;
		}
		if (global_departure_event_type == APP3)
		{
			Total_BW_APP3=Total_BW_APP3-Req_BW_APP3;
		}
	       if (global_departure_event_type == APP4)
		{
			Total_BW_APP4=Total_BW_APP4-Req_BW_APP4;
		}
       
printf(" Depart () APP type %d, channel_state%d, Total remaining BW %d \n",global_departure_event_type,channel_state,channel_BW-(Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4));
fprintf(fp,"D %d %f %d\n",global_departure_event_type,time,channel_BW-(Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4));

 if(channel_BW< (Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4))
	     channel_state = BUSY;
        else
	     channel_state = IDLE;
//if channel is busy, just see if any other application will get out

	if(channel_state==BUSY)
		{
				///
			temp_result=find_minimum_in_departure_list();
			time_next_event[2]=temp_result.timings_in_departure_list;
			global_departure_event_type=temp_result.type_of_app;
			global_self=temp_result.self;
			            printf("Depart () Next APP type %d , current time %f, Next Departure time %fNext Self\n",global_departure_event_type,time,time_next_event[2],global_self);
			fprintf(fp,"X %d %f %f %d %d\n",global_departure_event_type,time,time_next_event[2],channel_BW-(Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4),global_self);
			///
			


		}
	else{

	///if channel is empty, first try if something is there in queue. if it is there, see if included, it would meed bandwidth requirement
	//else if channel is empty, if nothing is there in queue


			if(q_len_app1 == 0 && q_len_app2 ==0 && q_len_app3 == 0&& q_len_app4 == 0)
				{
			                	printf(" All queues are empty, just calculate departures from present departure list");
						///
						temp_result=find_minimum_in_departure_list();
						time_next_event[2]=temp_result.timings_in_departure_list;
						global_departure_event_type=temp_result.type_of_app;
						global_self=temp_result.self;
						            printf("Depart () Next APP type %d , current time %f, Next Departure time %f\n",global_departure_event_type,time,time_next_event[2]);
						fprintf(fp,"X %d %f %f %d %d\n",global_departure_event_type,time,time_next_event[2],channel_BW-(Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4),global_self);

				}

			else//if queue have something
				{
		     		 printf("Depart() Various Queue Lengths 1Q:%d 2Q:%d 3Q:%d 4Q:%d current time %f\n ",q_len_app1, q_len_app2,q_len_app3,q_len_app4,time);


					if(global_scheme==0)
					{
						if( q_len_app1  != 0 )
						{
							--q_len_app1 ;
							temp_time = time + expon(mean_serv_time_app1);
							//delay = time - time_arrival[1];
							//tot_delay += delay;
							++no_cust_del;
				                  temp_queue_type=0;
				                  
						}

						else if( q_len_app2  != 0 && q_len_app1 == 0)
						{
							--q_len_app2 ;
							temp_time = time + expon(mean_serv_time_app2);
							//delay = time - time_arrival[1];
							//tot_delay += delay;
							++no_cust_del;
							temp_queue_type=1;		
						}

						else if( q_len_app3!= 0 && q_len_app2== 0 && q_len_app1 ==0 )
						{
							--q_len_app3;
							temp_time= time + expon(mean_serv_time_app3);
							//delay = time - time_arrival[1];
							//tot_delay += delay;
							++no_cust_del;
							temp_queue_type=2;
						}
						else if( q_len_app4!= 0 && q_len_app3== 0 && q_len_app2 ==0 && q_len_app1 ==0)
						{
					                --q_len_app4;
							temp_time = time + expon(mean_serv_time_app4);
							//delay = time - time_arrival[1];
							//tot_delay += delay;
							++no_cust_del;
							temp_queue_type=3;		
						}

					}
					else if(global_scheme==1)
					{

                                                temp_queue_type= max(q_len_app1,q_len_app2,q_len_app3,q_len_app4);
								if ( temp_queue_type == APP1 )
								{       	--q_len_app1 ;
							temp_time = time + expon(mean_serv_time_app1);
							//delay = time - time_arrival[1];
							//tot_delay += delay;
							++no_cust_del;
				                  temp_queue_type=0;
								}
								if ( temp_queue_type == APP2)
								{       --q_len_app2 ;
							temp_time = time + expon(mean_serv_time_app2);
							//delay = time - time_arrival[1];
							//tot_delay += delay;
							++no_cust_del;
							temp_queue_type=1;	
								}
								if ( temp_queue_type == APP3)
								{--q_len_app3;
							temp_time= time + expon(mean_serv_time_app3);
							//delay = time - time_arrival[1];
							//tot_delay += delay;
							++no_cust_del;
							temp_queue_type=2;
								}
							       if ( temp_queue_type == APP4)
								{      --q_len_app4;
							temp_time = time + expon(mean_serv_time_app4);
							//delay = time - time_arrival[1];
							//tot_delay += delay;
							++no_cust_del;
							temp_queue_type=3;	
								}

					}	else if(global_scheme==2)
					{

                                              temp_queue_type= max(q_len_app1,q_len_app2,q_len_app3,q_len_app4);
									if ( temp_queue_type == APP1 )
									{       //napp1++;
										Total_BW_APP1=Total_BW_APP1-Req_BW_APP1;
									}
									if ( temp_queue_type == APP2)
									{       //napp2++; 
										Total_BW_APP2=Total_BW_APP2-Req_BW_APP2;
									}
									if ( temp_queue_type == APP3)
									{       //napp3++;
										Total_BW_APP3=Total_BW_APP3-Req_BW_APP3;
									}
								       if ( temp_queue_type == APP4)
									{       //napp4++;
										Total_BW_APP4=Total_BW_APP4-Req_BW_APP4;
									}

				}
		/////////////////////////////////////////////////////////////////////////////////////////
				if ( temp_queue_type == APP1 )
				{       //napp1++;
					Total_BW_APP1=Total_BW_APP1+Req_BW_APP1;
				}
				if ( temp_queue_type == APP2)
				{       //napp2++; 
					Total_BW_APP2=Total_BW_APP2+Req_BW_APP2;
				}
				if ( temp_queue_type == APP3)
				{       //napp3++;
					Total_BW_APP3=Total_BW_APP3+Req_BW_APP3;
				}
			       if ( temp_queue_type == APP4)
				{       //napp4++;
					Total_BW_APP4=Total_BW_APP4+Req_BW_APP4;
				}

   				if(channel_BW< (Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4))
	    	 		{	 

					printf("Still not able to take ");

if(global_scheme!=2)
{
					if(global_scheme==0)
					{
						if ( temp_queue_type == APP1 )
						{
							Total_BW_APP1=Total_BW_APP1-Req_BW_APP1;
							napp1_drop++;
						}
						if ( temp_queue_type == APP2)
						{
							Total_BW_APP2=Total_BW_APP2-Req_BW_APP2;
							napp2_drop++;			
						}
						if ( temp_queue_type == APP3)
						{
							Total_BW_APP3=Total_BW_APP3-Req_BW_APP3;
							napp3_drop++;
						}
					       if ( temp_queue_type == APP4)
						{
							Total_BW_APP4=Total_BW_APP4-Req_BW_APP4;
							napp4_drop++;			
						}		
///////////////////////////////////////////////////////////////////////////////
//to do -here also we need to remove from app wait list, since we have already taken out from queue and dropped


	                          		if(temp_queue_type==global_app_wait_temp_app_type)
	                         	 	{
				                        	i=temp_queue_type;
								for(j=0;j< max_possible_apps;j++)
								{
									if(global_app_wait_list[i][j].expire_time< min_time_next_event)
									{
										min_time_next_event = global_app_wait_list[i][j].expire_time;
										temp_next=j;
									}
							                         	
								
		                          			}

							global_app_wait_list[temp_queue_type][temp_next].expire_time=1000000.00;
							global_app_wait_list[temp_queue_type][temp_next].type_of_app=100;
							global_app_wait_list[temp_queue_type][temp_next].valid=0;
							global_app_wait_temp_app_type=100;
		                                   printf("global app wait index %d %d  local least index %d %d ",global_app_wait_tempi ,global_app_wait_tempj,temp_queue_type,temp_next);
				 			//so in this case if the app tye of new choosen to be taken taken into channel 
							//and global minimum app type are same, just delete the earliest in that app category
		                                  //and now you find the new earliest app type to expire
		             
							temp_result_app_wait=find_minimum_in_app_wait_list();
							time_next_event[4]=temp_result_app_wait.expire_time;
					
						}
					else
	                         		{
		  					i=temp_queue_type;
							for(j=0;j< max_possible_apps;j++)
							{
								if(global_app_wait_list[i][j].expire_time< min_time_next_event)
								{
									min_time_next_event = global_app_wait_list[i][j].expire_time;
									temp_next=j;
								}
							                         	
								
		                          		}

							global_app_wait_list[temp_queue_type][temp_next].expire_time=1000000.00;
							global_app_wait_list[temp_queue_type][temp_next].type_of_app=100;
							global_app_wait_list[temp_queue_type][temp_next].valid=0;
						
								//till now do the same as above and now we dont need find the new, 
								//as we have not made any addition to older global app wait type
		                                         //and have just removed from other app type				

						}

					}
					else if(global_scheme==1)
					{
						if ( temp_queue_type == APP1 )
						{
							Total_BW_APP1=Total_BW_APP1-Req_BW_APP1;
							napp1_drop++;
						}
						if ( temp_queue_type == APP2)
						{
							Total_BW_APP2=Total_BW_APP2-Req_BW_APP2;
							napp2_drop++;			
						}
						if ( temp_queue_type == APP3)
						{
							Total_BW_APP3=Total_BW_APP3-Req_BW_APP3;
							napp3_drop++;
						}
					       if ( temp_queue_type == APP4)
						{
							Total_BW_APP4=Total_BW_APP4-Req_BW_APP4;
							napp4_drop++;			
						}		
///////////////////////////////////////////////////////////////////////////////
//to do -here also we need to remove from app wait list, since we have already taken out from queue and dropped


	                          		if(temp_queue_type==global_app_wait_temp_app_type)
	                         	 	{
				                        	i=temp_queue_type;
								for(j=0;j< max_possible_apps;j++)
								{
									if(global_app_wait_list[i][j].expire_time< min_time_next_event)
									{
										min_time_next_event = global_app_wait_list[i][j].expire_time;
										temp_next=j;
									}
							                         	
								
		                          			}

							global_app_wait_list[temp_queue_type][temp_next].expire_time=1000000.00;
							global_app_wait_list[temp_queue_type][temp_next].type_of_app=100;
							global_app_wait_list[temp_queue_type][temp_next].valid=0;
							global_app_wait_temp_app_type=100;
		                                   printf("global app wait index %d %d  local least index %d %d ",global_app_wait_tempi ,global_app_wait_tempj,temp_queue_type,temp_next);
				 			//so in this case if the app tye of new choosen to be taken taken into channel 
							//and global minimum app type are same, just delete the earliest in that app category
		                                  //and now you find the new earliest app type to expire
		             
							temp_result_app_wait=find_minimum_in_app_wait_list();
							time_next_event[4]=temp_result_app_wait.expire_time;
					
						}
					else
	                         		{
		  					i=temp_queue_type;
							for(j=0;j< max_possible_apps;j++)
							{
								if(global_app_wait_list[i][j].expire_time< min_time_next_event)
								{
									min_time_next_event = global_app_wait_list[i][j].expire_time;
									temp_next=j;
								}
							                         	
								
		                          		}

							global_app_wait_list[temp_queue_type][temp_next].expire_time=1000000.00;
							global_app_wait_list[temp_queue_type][temp_next].type_of_app=100;
							global_app_wait_list[temp_queue_type][temp_next].valid=0;
						
								//till now do the same as above and now we dont need find the new, 
								//as we have not made any addition to older global app wait type
		                                         //and have just removed from other app type				

						}

					}

//////////////////////////////////////////////////////////////////////////////

}

						   
						temp_result=find_minimum_in_departure_list();
						time_next_event[2]=temp_result.timings_in_departure_list;
						global_departure_event_type=temp_result.type_of_app;
						global_self=temp_result.self;
						printf("Depart () Dropped Next APP type %d , current time %f, Next Departure time %f %d\n",global_departure_event_type,time,time_next_event[2],global_self);


						//for( i=1; i<=que_len; ++i )
						//time_arrival[i] = time_arrival[i+1];
						flag_departure_calculated=1;




					}
			        else
				     {//if we are able to admit from queue to channel
	//to remove from app wait queue

if(global_scheme!=2)
{
		                          	if(temp_queue_type==global_app_wait_temp_app_type)
		                         	{
				                        	i=temp_queue_type;
								for(j=0;j< max_possible_apps;j++)
								{
									if(global_app_wait_list[i][j].expire_time< min_time_next_event)
									{
										min_time_next_event = global_app_wait_list[i][j].expire_time;
										temp_next=j;
									}
							                         	
								
		                          			}

							global_app_wait_list[temp_queue_type][temp_next].expire_time=1000000.00;
							global_app_wait_list[temp_queue_type][temp_next].type_of_app=100;
							global_app_wait_list[temp_queue_type][temp_next].valid=0;
							global_app_wait_temp_app_type=100;
		                                   printf("global app wait index %d %d  local least index %d %d ",global_app_wait_tempi ,global_app_wait_tempj,temp_queue_type,temp_next);
				 			//so in this case if the app tye of new choosen to be taken taken into channel 
							//and global minimum app type are same, just delete the earliest in that app category
		                                  //and now you find the new earliest app type to expire
		             
							temp_result_app_wait=find_minimum_in_app_wait_list();
							time_next_event[4]=temp_result_app_wait.expire_time;
						
						}
						else
		                         	{
		  					i=temp_queue_type;
							for(j=0;j< max_possible_apps;j++)
							{
								if(global_app_wait_list[i][j].expire_time< min_time_next_event)
								{
									min_time_next_event = global_app_wait_list[i][j].expire_time;
									temp_next=j;
								}
							                         	
								
		                          		}

							global_app_wait_list[temp_queue_type][temp_next].expire_time=1000000.00;
							global_app_wait_list[temp_queue_type][temp_next].type_of_app=100;
							global_app_wait_list[temp_queue_type][temp_next].valid=0;
						
								//till now do the same as above and now we dont need find the new, 
								//as we have not made any addition to older global app wait type
		                                         //and have just removed from other app type				

						}

		

	                         
						//update the time in the departure list
						printf("Depart() Update in Dep APP type%d APP Leave Time %f BW %d  Current time%f\n",user_type,temp_time,Total_BW_APP1+Total_BW_APP2+Total_BW_APP3+Total_BW_APP4,time);
						update_App_time_in_departure_list(temp_queue_type,temp_time,global_self);//this needs to be calculated
						//pick up latest time
}
						temp_result=find_minimum_in_departure_list();
						time_next_event[2]=temp_result.timings_in_departure_list;
						global_departure_event_type=temp_result.type_of_app;
						global_self=temp_result.self;
						printf("Depart () Next APP type %d , current time %f, Next Departure time %f\n",global_departure_event_type,time,time_next_event[2]);


						//for( i=1; i<=que_len; ++i )
						//time_arrival[i] = time_arrival[i+1];
						flag_departure_calculated=1;
				 	 }
				}
		}
}


float expon(float lambda)
{
	float exp;
	float x,y;
	x = rand();
	y =  x/RAND_MAX;
	exp = -lambda * log(y);
	return exp;
}


void review_char(void)
{
//In this we review the system characterstics every 2 minutes
if( (global_number_of_app_arrived<tot_req)||(global_number_of_app_departured < tot_req-2) )
time_next_event[3]=time+Periodic_review_event_duration;
else
time_next_event[3]=1000000.00;
printf("\n\nreview_char(void) System Characterstics getting reviewed at %f\n",time);
fprintf(fp,"RC %f \n",time);
}
void depart_app_wait(void)
{
//make the departing entry invalid
struct details_node_app_wait_list  temp_result_app_wait;

	switch(global_app_wait_list[global_app_wait_tempi][global_app_wait_tempj].type_of_app)
		{
		  		 case 0:
		   			napp1_drop++;
					q_len_app1--;
		   			break;
				 case 1:
					napp2_drop++;
					q_len_app2--;
					break;
				 case 2:
					napp2_drop++;
					q_len_app3--;
					break;
				 case 3:
					napp3_drop++;
					q_len_app4--;
					break;

		}



global_app_wait_list[global_app_wait_tempi][global_app_wait_tempj].expire_time=1000000.00;
global_app_wait_list[global_app_wait_tempi][global_app_wait_tempj].type_of_app=100;
global_app_wait_list[global_app_wait_tempi][global_app_wait_tempj].self=100;
global_app_wait_list[global_app_wait_tempi][global_app_wait_tempj].valid=0;
printf("\n depart_app_wait(void) %d %d %d %d %d %d %d %d",napp1_drop,napp2_drop,napp3_drop,napp4_drop,q_len_app1,q_len_app2,q_len_app3,q_len_app4);
if(q_len_app1 == 0 && q_len_app2 ==0 && q_len_app3 == 0&& q_len_app4 == 0)
{printf("\n depart_app_wait(void)   there wont be anything in app wait \n");
time_next_event[4]=1000000.00;
}else
		{
//find the next departing from the app wait list
temp_result_app_wait=find_minimum_in_app_wait_list();
			time_next_event[4]=temp_result_app_wait.expire_time;
//application in app wait queue has expired
}printf(" \n\n depart_app_wait(void)  next departure %f time %f\n",temp_result_app_wait.expire_time,time);
fprintf(fp,"DA %f %f\n",time,time_next_event[4]);
}

void report(void)
{

	//float avg_delay,ser_uti,avg_que_len;
	//avg_delay = tot_delay/no_cust_del;
	//ser_uti = tot_ser/time;
	//avg_que_len = tot_que/time;

	/*printf(" The avg delay in Que = %f\n", avg_delay);
	printf(" The Server uti = %f\n", ser_uti);
	printf(" The avg Que len = %f\n", avg_que_len);
	printf(" Max que len was = %d\n",max_que_len);*/



	printf(" napp1  =  %d, napp2  = %d, napp3  = %d, napp4=%d\n",napp1,napp2,napp3,napp4);
	printf(" napp1_drop =  %d, napp2_drop = %d, napp3_drop = %d,  napp4_drop=%d\n\n",napp1_drop,napp2_drop,napp3_drop,napp4_drop);
        printf("Total arrived%d Total Departured%d",global_number_of_app_arrived,global_number_of_app_departured); 

	printf(" Total Dropped = %d\n\n",napp1_drop+napp2_drop+napp3_drop+napp4_drop);
	printf(" napp1_self  =  %d, napp1_self = %d, napp1_self = %d, napp1_self=%d\n",napp1_self,napp2_self,napp3_self,napp1_self);
printf(" Drop Self Generated & Dropped napp1_self_Drop =  %d, napp2_self_Drop= %d, napp3_self_Drop = %d,  napp4_self_Drop=%d\n\n",napp1_self_Drop,napp2_self_Drop,napp3_self_Drop,napp4_self_Drop);

fp2_log=fopen("log_overall.txt","a+");
fprintf(fp2_log,"%d %d %d %d %d %d %d %d %d %d %d %d\n",global_number_of_app_arrived-1,napp1_drop+napp2_drop+napp3_drop+napp4_drop,napp1_self+napp2_self+napp3_self+napp1_self,napp1_self_Drop+napp2_self_Drop+napp3_self_Drop+napp4_self_Drop,napp1_self,napp2_self,napp3_self,napp1_self,napp1_self_Drop,napp2_self_Drop,napp3_self_Drop,napp4_self_Drop );
fclose(fp2_log);
}


int max(int a,int b,int c,int d)
{
  int temp[4],min=100000,j,temp_next;
  temp[0]=a;
  temp[1]=a;
  temp[2]=c;
  temp[3]=d;

  for(j=0;j< 4;j++)
	{
	  if( temp[j]< min)
		{
	       	min = temp[j];
			temp_next=j;
		}
	}
  return temp_next;
}



